package com.yys.apm.collect;

import com.yys.apm.boot.AgentBootLoader;
import com.yys.apm.boot.ApmAgentManager;
import com.yys.apm.config.ApmConfig;
import com.yys.apm.model.CollectInfo;
import com.yys.apm.logger.ILogger;
import com.yys.apm.logger.LoggerManager;
import com.yys.apm.utils.ApmAgentUtil;
import javassist.CtMethod;

import java.lang.reflect.Modifier;
import java.util.concurrent.*;

/**
 * 采集器基础实现
 *
 * @author Yingsheng Ye
 * @date 2021-03-19 21:20
 */
public abstract class AbstractApmCollects {

    private static final ILogger logger = LoggerManager.getLogger(AbstractApmCollects.class);

    // 统一线程池
    private final static ExecutorService threadService;

    private static long rejectedCount = 0;

    private static String CLIENT_URL;

    private static String SECRET_KEY;

    private ApmAgentManager agentManager;


    AbstractApmCollects() {
        this.agentManager = ApmAgentManager.getInstance();
        CLIENT_URL = agentManager.properties.getProperty(ApmConfig.PUSH_CLIENT_URL);
        SECRET_KEY = agentManager.properties.getProperty(ApmConfig.PUSH_SECRET_KEY);
    }

    static {
        threadService = new ThreadPoolExecutor(10, 100,
                20000L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>(1000),
                new RejectedExecutionHandler() {
                    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                        rejectedCount++;
                        logger.info("execute Task rejected from " +
                                executor.toString() + " rejectedCount:" + rejectedCount);
                    }

                });

    }

    void execute(CollectInfo dataModel) {
        if (this.agentManager.isExtractData()) {
            threadService.execute(() -> {
                logger.info("请求参数==>" + dataModel);
                String res = ApmAgentUtil.sendHttpRequest(CLIENT_URL, ApmAgentUtil.buildRequestPkg(dataModel, "collectService", SECRET_KEY));
                logger.info("输出结果==>" + res);
            });
        }
    }


    public byte[] transform(AgentBootLoader agentLoader) throws Exception {
        CtMethod[] methods = agentLoader.getCtClass().getDeclaredMethods();
        for (CtMethod m : methods) {
            // 屏蔽非公共方法
            if (!Modifier.isPublic(m.getModifiers())) {
                continue;
            }
            // 屏蔽静态方法
            if (Modifier.isStatic(m.getModifiers())) {
                continue;
            }
            // 屏蔽本地方法
            if (Modifier.isNative(m.getModifiers())) {
                continue;
            }
            agentLoader.agentMethod(m, setBuild(agentLoader.getClassName(), m));
        }
        return agentLoader.getCtClass().toBytecode();
    }

    protected abstract AgentBootLoader.MethodSourceBuild setBuild(String className, CtMethod m);

}
